#pragma once

#include "align.h"
#include <QComboBox>
#include "../../layout/layout.hpp"
#include "../../select/select_cmd.hpp"
#include "../../utils/kutils.h"
#include "qbe/src/utils/utils.hpp"
#include "qlib/geo/polygon.h"
#include "qlib/tools/clipper_tools.h"
namespace qbe::editing::Align {

void exit(ecs::Query query, state::AllModeType enter_mode) {
  int a = 0;
}
void init(entt::registry& reg, ecs::Commands commands, ecs::Query query) {}

void update(entt::registry& ecs_reg, ecs::Query query, ecs::Bus& bus, ecs::EventWriter<msg::RenderEvent> event) {
  auto& state = query.get_resource<state::State>();

  // 仅在模式执行
  if (state.getEditingMode() != state::EditingModeType::Align)
    return;

  //获取当前操作的Cell
  auto& cmd = query.get_resource<layout::CellCmd>();
  auto& layout_cmd = query.get_resource<layout::LayoutCmd>();
  auto& select_cmd = query.get_resource<select::SelectCmd>();
  auto cell = cmd.get_cell();
  auto& reg = cell->reg;
  auto& cell_state = query.get_resource<layout::CellState>();
  auto& undoRedoModule = query.get_resource<undoRedoT::UndoRedoModule>();
  auto& model = query.get_resource<AlignModel>();
  auto& layer_interface = query.get_resource<tools::LayerInterfaceObjcet>();
  model.ele_bbBox.clear();
  model.select_arr.clear();
  model.select_arr_without_no_layer.clear();
  model.cell = cell;
  model.layer_interface = layer_interface;

  //获取选择对象
  std::vector<std::pair<entt::entity, uint32_t>>& select_arr = model.select_arr;
  std::unordered_map<entt::entity, bool> select_orders = select_cmd.get_select_orders();
  // for (auto [e] : reg.view<select::SelectTag>().each()) {
  for (const auto& pair : select_orders) {
    entt::entity e = pair.first;
    auto ellipse_ptr = reg.try_get<qlib::Ellipse::s_ptr>(e);
    if (ellipse_ptr) {
      qlib::Polygon::s_ptr pol = (*ellipse_ptr)->to_polygon();
      select_arr.push_back(std::make_pair(e, pol->layer));
    }

    auto rectangle_ptr = reg.try_get<qlib::Rectangle::s_ptr>(e);
    if (rectangle_ptr) {
      qlib::Polygon::s_ptr pol = (*rectangle_ptr)->to_polygon();
      select_arr.push_back(std::make_pair(e, pol->layer));
    }

    auto polygon_ptr = reg.try_get<qlib::Polygon::s_ptr>(e);
    if (polygon_ptr) {
      select_arr.push_back(std::make_pair(e, (*polygon_ptr)->layer));
    }

    auto fan_ptr = reg.try_get<qlib::Fan::s_ptr>(e);
    if (fan_ptr) {
      qlib::Polygon::s_ptr pol = (*fan_ptr)->to_polygon();
      select_arr.push_back(std::make_pair(e, pol->layer));
    }

    auto path_ptr = reg.try_get<qlib::Path::s_ptr>(e);
    if (path_ptr) {
      qlib::PolygonPtrArray pols;
      (*path_ptr)->to_polygons(false, qlib::Tag{0, 0}, pols);
      select_arr.push_back(std::make_pair(e, (*path_ptr)->layer));
    }

    auto text_ptr = reg.try_get<qlib::Text::s_ptr>(e);
    if (text_ptr) {
      qlib::PolygonPtrArray pols = (*text_ptr)->to_polygons();
      select_arr.push_back(std::make_pair(e, pols[0]->layer));
    }

    auto ref_ptr = reg.try_get<qlib::Reference::s_ptr>(e);
    if (ref_ptr) {
      std::shared_ptr<qlib::Polygon> pol;
      select_arr.push_back(std::make_pair(e, -1));
    }

    auto label_ptr = reg.try_get<qlib::Label::s_ptr>(e);
    if (label_ptr) {
      qlib::PolygonPtrArray pols = (*label_ptr)->to_polygons();
      select_arr.push_back(std::make_pair(e, pols[0]->layer));
    }

    auto kay_point_ptr = reg.try_get<qlib::KeyPoint::s_ptr>(e);
    if (kay_point_ptr) {
      qlib::PolygonPtrArray pols = (*kay_point_ptr)->to_polygons();
      select_arr.push_back(std::make_pair(e, pols[0]->layer));
    }

    auto pin_ptr = reg.try_get<qlib::Pin::s_ptr>(e);
    if (pin_ptr) {
      qlib::Polygon::s_ptr pol = (*pin_ptr)->to_polygon();
      select_arr.push_back(std::make_pair(e, pol->layer));
    }

    auto ruler_ptr = reg.try_get<qlib::Ruler::s_ptr>(e);
    if (ruler_ptr) {
      qlib::Polygon::s_ptr pol = (*ruler_ptr)->to_polygon();
      select_arr.push_back(std::make_pair(e, pol->layer));
    }

    auto view_area_3d_ptr = reg.try_get<qlib::ViewArea3D::s_ptr>(e);
    if (view_area_3d_ptr) {
      select_arr.push_back(std::make_pair(e, -1));
    }

    auto section_area_3d_ptr = reg.try_get<qlib::SectionArea3D::s_ptr>(e);
    if (section_area_3d_ptr) {
      select_arr.push_back(std::make_pair(e, -1));
    }
  }
  if (select_arr.empty()) {
    state.exit();
    return;
  }

  qbe::UiMessage::Align_Open open_msg;
  auto& select_model = query.get_resource<select::OverallModel>();
  if (select_model.op_type == qbe::select::OverallOperatorType::Box || select_model.op_type == qbe::select::OverallOperatorType::All) {
    model.is_box_select = true;
  } else {
    model.is_box_select = false;
  }

  std::vector<std::pair<entt::entity, uint32_t>>& select_arr_without_no_layer = model.select_arr_without_no_layer;
  for (auto&& sel : select_arr) {

    auto view_area_3d_ptr = reg.try_get<qlib::ViewArea3D::s_ptr>(sel.first);
    auto section_area_3d_ptr = reg.try_get<qlib::SectionArea3D::s_ptr>(sel.first);
    auto ruler_ptr = reg.try_get<qlib::Ruler::s_ptr>(sel.first);

    if (!view_area_3d_ptr && !section_area_3d_ptr && !ruler_ptr) {
      select_arr_without_no_layer.push_back(sel);
    }
  }

  if (model.is_box_select == true || select_arr_without_no_layer.size() < 2) {
    open_msg.layerRadioButtonState = false;
  } else {
    //若全部是引脚，不能进行图层对齐
    bool is_all_pin = true;
    for (auto it : model.select_arr) {
      auto pin_ptr = reg.try_get<qlib::Pin::s_ptr>(it.first);
      if (pin_ptr) {
        continue;
      }
      is_all_pin = false;
    }
    if (is_all_pin == true) {
      open_msg.layerRadioButtonState = false;
    } else {
      open_msg.layerRadioButtonState = true;
      //if (m_align->getLayer()) {
      layer(model);
      //}
    }
  }

  if (model.is_open_ui == false) {
    //std::map<entt::entity, QComboBox *> ele_combobox;
    for (auto item : model.ele_combobox) {
      open_msg.comboboxs.push_back(item.second);
    }

    bus.send(open_msg);
    model.is_open_ui = true;
  }

  auto res_ok = bus.receive<qbe::UiMessage::Align_Ok>();
  if (!res_ok.empty()) {
    qbe::UiMessage::Align_Ok ok_msg = std::any_cast<qbe::UiMessage::Align_Ok>(res_ok[0]);
    onOk(query, model, ok_msg);

    if (ok_msg.is_apply == false) {
      state.exit();
      if (model.is_open_ui == true) {
        bus.send(qbe::UiMessage::Align_Close());
        model.is_open_ui = false;
      }
    }
  }

  auto res_close = bus.receive<qbe::UiMessage::Align_Close>();
  if (!res_close.empty()) {
    state.switchMode(state::EditingModeType::None);
    model.is_open_ui = false;
    for (auto i : model.ele_combobox) {
      delete i.second;
    }
    model.ele_combobox.clear();
  }
}
void post(entt::registry& reg, ecs::Commands commands, ecs::Query query, ecs::Bus& bus) {}

void onOk(ecs::Query query, AlignModel& model, qbe::UiMessage::Align_Ok& ok_msg) {
  auto& undoRedoModule = query.get_resource<undoRedoT::UndoRedoModule>();
  auto& layout_cmd = query.get_resource<layout::LayoutCmd>();
  //如果是按图层对齐，过滤掉引脚
  if (ok_msg.reference_standard == 1) {
    //选中不带有图层的对象，进行对齐时，若使用图层对齐，过滤不带有图层的对象
    model.select_arr.clear();
    std::vector<std::pair<entt::entity, uint32_t>>& selected_elements_without_no_layer = model.select_arr_without_no_layer;
    for (auto it : selected_elements_without_no_layer) {
      auto pin_ptr = model.cell->reg.try_get<qlib::Pin::s_ptr>(it.first);
      if (pin_ptr) {
        continue;
      }

      model.select_arr.push_back(it);
    }
  }

  // if (m_align->config_data_change == false)
  //   return;

  if (model.select_arr.size() >= 2) {
    qlib::Vec2d off;
    std::vector<qlib::Vec2d> max_box;
    if (ok_msg.reference_standard == 0) {
      if (model.is_box_select == true) {
        // 框选求所有包围和对齐

        std::vector<entt::entity> select_entitys;
        for (auto pair : model.select_arr) {
          select_entitys.push_back(pair.first);
        }
        auto graphs = qbe::auxiliary::getGraph(model.cell, select_entitys);
        max_box = qbe::auxiliary::calBonndingBox(graphs);
      } else {
        // 点选以第一图形包围盒对齐

        std::vector<entt::entity> first_entitys = {model.select_arr[0].first};
        auto graphs = qbe::auxiliary::getGraph(model.cell, first_entitys);
        max_box = qbe::auxiliary::calBonndingBox(graphs);
      }
      for (auto ele : model.select_arr) {
        std::vector<entt::entity> first_entitys = {ele.first};
        auto graphs = qbe::auxiliary::getGraph(model.cell, first_entitys);
        std::vector<qlib::Vec2d> max_box_ele = qbe::auxiliary::calBonndingBox(graphs);
        model.ele_bbBox.insert({ele.first, max_box_ele});
      }
    } else {
      for (auto ele : model.select_arr) {
        auto ref_ptr = model.cell->reg.try_get<qlib::Reference::s_ptr>(ele.first);
        if (ref_ptr) {
          std::vector<qlib::Vec2d> box;
          auto combox = model.ele_combobox.find(ele.first);
          auto select_layer_text = combox->second->currentText();
          auto split_texts = select_layer_text.split("/");
          int select_layer = split_texts[split_texts.size() - 1].toInt();

          qbe::auxiliary::BoundingBox bonnding_box;

          qlib::PolygonPtrArrayMap polygonsMap;
          (*ref_ptr)->get_polygons(true, true, -1, false, qlib::Tag{0, 0}, polygonsMap, false);

          for (auto pair : polygonsMap) {
            for (auto poly : pair.second) {
              if (poly->layer == select_layer) {
                auto bound_box = poly->bounding_box();
                bonnding_box.addPoints(
                    std::vector<qlib::Vec2d>({qlib::Vec2d(bound_box[0].x, bound_box[0].y), qlib::Vec2d(bound_box[1].x, bound_box[1].y)}));
              }
            }
          }

          qlib::LabelPtrArrayMap labelsMap;
          (*ref_ptr)->get_labels(true, -1, false, qlib::Tag{0, 0}, labelsMap, false);

          for (auto pair : labelsMap) {
            for (auto lable : pair.second) {
              if (lable->layer == select_layer) {
                auto bound_box = lable->bounding_box();
                bonnding_box.addPoints(
                    std::vector<qlib::Vec2d>({qlib::Vec2d(bound_box[0].x, bound_box[0].y), qlib::Vec2d(bound_box[1].x, bound_box[1].y)}));
              }
            }
          }

          qlib::PathPtrArrayMap pathsMap;
          (*ref_ptr)->get_paths(true, -1, false, qlib::Tag{0, 0}, pathsMap, false);

          for (auto pair : pathsMap) {
            for (auto line : pair.second) {
              if (line->layer == select_layer) {
                auto bound_box = line->bounding_box();
                bonnding_box.addPoints(
                    std::vector<qlib::Vec2d>({qlib::Vec2d(bound_box[0].x, bound_box[0].y), qlib::Vec2d(bound_box[1].x, bound_box[1].y)}));
              }
            }
          }

          model.ele_bbBox.insert({ele.first, std::vector<qlib::Vec2d>({bonnding_box.min, bonnding_box.max})});
        } else {

          std::vector<entt::entity> first_entitys = {ele.first};
          auto graphs = qbe::auxiliary::getGraph(model.cell, first_entitys);
          auto max_box_ele = qbe::auxiliary::calBonndingBox(graphs);
          model.ele_bbBox.insert({ele.first, max_box_ele});
        }
      }

      if (model.is_box_select == true) {
        // 框选使用层对齐暂时没有使用
        qbe::auxiliary::BoundingBox bonnding_box;
        for (auto bd_box : model.ele_bbBox) {
          bonnding_box.addPoints(bd_box.second);
        }
        max_box.push_back(bonnding_box.min);
        max_box.push_back(bonnding_box.max);
      } else {
        auto box = model.ele_bbBox.find(model.select_arr[0].first)->second;
        max_box.push_back(box[0]);
        max_box.push_back(box[1]);
      }
    }
    undoRedoModule.start(model.cell);
    if (ok_msg.align_mode == qbe::UiMessage::Align_Ok::AlignMode::LeftAligned) {  // 左对齐
      double distance = 0;
      for (auto ele : model.select_arr) {
        undoRedoModule.change(ele.first);
        off.x = max_box[0].x - model.ele_bbBox.find(ele.first)->second[0].x;
        off.y = 0;
        utils::translate(model.cell->reg, ele.first, qlib::Vec2d(off.x, off.y));
        if (ok_msg.is_distance_open == true) {
          utils::translate(model.cell->reg, ele.first, qlib::Vec2d(distance, 0));
          distance += ok_msg.align_distance;
        }
        layout_cmd.update(ele.first);
      }
    } else if (ok_msg.align_mode == qbe::UiMessage::Align_Ok::AlignMode::RightAligned) {
      // 右对齐
      double distance = 0;
      for (auto ele : model.select_arr) {
        undoRedoModule.change(ele.first);
        off.x = max_box[1].x - model.ele_bbBox.find(ele.first)->second[1].x;
        off.y = 0;
        utils::translate(model.cell->reg, ele.first, qlib::Vec2d(off.x, off.y));
        if (ok_msg.is_distance_open == true) {
          utils::translate(model.cell->reg, ele.first, qlib::Vec2d(distance, 0));
          distance -= ok_msg.align_distance;
        }
        layout_cmd.update(ele.first);
      }
    } else if (ok_msg.align_mode == qbe::UiMessage::Align_Ok::AlignMode::TopAligned) {
      // 上对齐
      double distance = 0;
      for (auto ele : model.select_arr) {
        undoRedoModule.change(ele.first);
        off.x = 0;
        std::vector<qlib::Vec2d> obj_box = model.ele_bbBox.find(ele.first)->second;
        off.y = max_box[1].y - obj_box[1].y;
        utils::translate(model.cell->reg, ele.first, qlib::Vec2d(off.x, off.y));

        if (ok_msg.is_distance_open == true) {
          utils::translate(model.cell->reg, ele.first, qlib::Vec2d(0, distance));
          distance -= ok_msg.align_distance;
        }
        layout_cmd.update(ele.first);
      }
    } else if (ok_msg.align_mode == qbe::UiMessage::Align_Ok::AlignMode::BottomAligned) {
      // 下对齐
      double distance = 0;
      for (auto ele : model.select_arr) {
        undoRedoModule.change(ele.first);
        off.x = 0;
        off.y = max_box[0].y - model.ele_bbBox.find(ele.first)->second[0].y;
        utils::translate(model.cell->reg, ele.first, qlib::Vec2d(off.x, off.y));

        if (ok_msg.is_distance_open == true) {
          utils::translate(model.cell->reg, ele.first, qlib::Vec2d(0, distance));
          distance += ok_msg.align_distance;
        }
        layout_cmd.update(ele.first);
      }
    } else if (ok_msg.align_mode == qbe::UiMessage::Align_Ok::AlignMode::HorizontallyCenterAligned) {
      qlib::Vec2d center;
      if (model.is_box_select == true) {
        // 横向中线以横线最靠下的图形为基准
        for (auto&& i : model.ele_bbBox) {
          if (abs(max_box[0].y - i.second[0].y) < 10e-5) {
            center = (i.second[0] + i.second[1]) / 2;
          }
        }
      } else {
        center = (max_box[0] + max_box[1]) / 2;
      }

      // 横向中线对齐
      double distance = 0;
      for (auto ele : model.select_arr) {
        auto center_1 = (model.ele_bbBox.find(ele.first)->second[0] + model.ele_bbBox.find(ele.first)->second[1]) / 2;
        undoRedoModule.change(ele.first);
        off.x = 0;
        off.y = center.y - center_1.y;
        utils::translate(model.cell->reg, ele.first, qlib::Vec2d(off.x, off.y));

        if (ok_msg.is_distance_open == true) {
          utils::translate(model.cell->reg, ele.first, qlib::Vec2d(distance, 0));
          distance += ok_msg.align_distance;
        }
        layout_cmd.update(ele.first);
      }
    } else if (ok_msg.align_mode == qbe::UiMessage::Align_Ok::AlignMode::VerticallyCenterAligned) {
      qlib::Vec2d center;
      if (model.is_box_select == true) {
        // 竖向中线对齐以图形竖线做靠左的图形为基准
        for (auto&& i : model.ele_bbBox) {
          if (abs(max_box[0].x - i.second[0].x) < 10e-5) {
            center = (i.second[0] + i.second[1]) / 2;
          }
        }
      } else {
        center = (max_box[0] + max_box[1]) / 2;
      }
      // 竖向中线对齐
      double distance = 0;
      for (auto ele : model.select_arr) {
        auto center_1 = (model.ele_bbBox.find(ele.first)->second[0] + model.ele_bbBox.find(ele.first)->second[1]) / 2;

        undoRedoModule.change(ele.first);
        off.x = center.x - center_1.x;
        off.y = 0;
        utils::translate(model.cell->reg, ele.first, qlib::Vec2d(off.x, off.y));

        if (ok_msg.is_distance_open == true) {
          utils::translate(model.cell->reg, ele.first, qlib::Vec2d(0, distance));
          distance += ok_msg.align_distance;
        }
        layout_cmd.update(ele.first);
      }
    }
  }
  if (model.select_arr.size() >= 2) {
    // for (int i = 0; i < selected_elements.size(); ++i) {
    //   pReceivers[i]->PrepareNewData(selected_elements[i]->m_graph);
    //   LayoutCtrlData::updateQuadTreeNode(selected_elements[i]);
    // }
  }
  undoRedoModule.end();

  // LayoutCtrlData::updateView();

  model.ele_combobox.clear();

  for (auto i : model.ele_combobox) {
    delete i.second;
  }
  // for (auto ele : selected_elements) {
  //   ele->selectedHighlight();
  //   if (ele->getEleType() == ElememtType::REFERENCE) {
  //     dynamic_cast<ReferenceNode*>(ele)->updateCachaData();
  //     LayoutCtrlData::updateQuadTreeNode(ele);
  //   }
  // }

  // LayoutCtrlData::cancelToolBarHighLight();
  // m_align->config_data_change = false;

  auto& sele_event_writer = query.get_event_writer<select::Event>();
  sele_event_writer.send({select::Code::SelectUpdate});
  sele_event_writer.send({select::Code::HoverUpdate});
}
}  // namespace qbe::editing::Align